﻿using Nemerle.Collections;
using Nemerle.ComputationExpressions;
using Nemerle.ComputationExpressions.Async;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

using MsCci = Microsoft.Cci;

using Nemerle2.Compiler;

namespace MetadataReader.CCI
{
  internal module Utils
  {
    public Split[T](this source : Seq[T], predicate : T -> bool) : List[T] * List[T]
    {
      def list1 = List();
      def list2 = List();
      
      foreach (elem in source)
        if (predicate(elem))
          list1.Add(elem);
        else
          list2.Add(elem);
          
      (list1, list2)
    }
    
    public ParallelForEach[T](this source : Seq[T], action : T -> void) : void
    {
      def actionDelegate : Action[T] = action;
      def waitHandles = source.MapToArray(a => actionDelegate.BeginInvoke(a, null, null).AsyncWaitHandle);
      _ = Threading.WaitHandle.WaitAll(waitHandles);
      //foreach (x in source.MapToArray(e => (comp async action(e)).Start()))
      //  _ = x.Result;
    }
    
    public ParallelMap[TIn, TOut](this source : Seq[TIn], convert : TIn -> TOut) : Seq[TOut]
    {
      source.MapToArray(e => (comp async return convert(e)).Start()).MapToArray(_.Value)
      
      //def actionDelegate : Func[TIn, TOut] = convert;
      //def results = source.MapToArray(a => actionDelegate.BeginInvoke(a, null, null));
      //def waitHandles = results.MapToArray(_.AsyncWaitHandle);
      //_ = Threading.WaitHandle.WaitAll(waitHandles);
      //results.MapToArray(actionDelegate.EndInvoke)
    }
    
    public GetFullName(this typeDef : MsCci.ITypeReference) : string
    {
      // VladD2: TODO: Реализовать правельное для немерла форматирование типов (например, массивы на сегодня не должны форматироваться правильно).
      // Возможно для этого можно воспользоваться типом MsCci.TypeNameFormatter (сделав его наследника).
      MsCci.TypeHelper.GetTypeName(typeDef, MsCci.NameFormattingOptions.UseTypeKeywords)
    }

    public static HasAttribute(this attributes : Seq[MsCci.ICustomAttribute], fullName : string) : bool
    {
      //_Eter_ : при использовании GetFullName с опцией UseTypeKeywords метод работает в два раза дольше
      attributes.Any(a => MsCci.TypeHelper.GetTypeName(a.Type) == fullName);
    }

    public static FindAttribute(this attributes : Seq[MsCci.ICustomAttribute], fullName : string) : Seq[MsCci.ICustomAttribute]
    {
      //_Eter_ : при использовании GetFullName с опцией UseTypeKeywords метод работает в два раза дольше
      attributes.Where(a => MsCci.TypeHelper.GetTypeName(a.Type) == fullName );
    }

    public static HasAttributes(this attributes : Seq[MsCci.ICustomAttribute], params fullNames : array[string]) : bool
    {
      //_Eter_ : при использовании GetFullName с опцией UseTypeKeywords метод работает в два раза дольше
      attributes.Any(a => fullNames.Contains(MsCci.TypeHelper.GetTypeName(a.Type)));
    }

    //public static AddMessage(this assembly : IReferencedAssembly, msg : Msg) : void
    //{
    //  (assembly :> CciReferencedAssembly).AddMessage(msg);
    //}

     public static IsExtension(this method : MsCci.IMethodDefinition) : bool
     {
       method.IsStatic
        && method.Attributes.HasAttributes(Constants.ExtensionAttributeFullName,
                                           Constants.SystemExtensionAttributeFullName)
     }

  }
}
